home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Interactive 7
/
PC World Interactive 7.iso
/
program
/
cprog.EXE
/
OBJ2ASM.ZIP
/
OUTARGET.C
< prev
next >
Wrap
Text File
|
1991-10-02
|
21KB
|
625 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "o.h"
/*
** Local Prototypes
*/
char *seg_name( int, word * );
char *grp_name( int );
void get_seg( char *, FIX_T *, int, void *, int );
void assume( int, int, int );
FIXER_T fix_type[] = {
1, "db", "low ", /* LOBYTE */
2, "dw", "offset ", /* OFFSET */
2, "dw", "seg ", /* BASE */
4, "dd", "ptr ", /* POINTER */
1, "db", "high ", /* HIBYTE */
2, "dw", "offset " }; /* Loader-resolved */
/* OFFSET */
char *seg_name( index, size )
int index;
word *size;
{
SEG_T *segment_rec;
NAME_T *name_rec;
seg_search.index = index;
segment_rec = (SEG_T *)find( (char *)&seg_search, segment_tree,
TC seg_compare, NULL );
if ( segment_rec == NULL ) fmt_error( "Undefinded segment" );
*size = segment_rec->length;
name_search.index = segment_rec->name;
name_rec = (NAME_T *)find( (char *)&name_search, name_tree,
TC name_compare, NULL );
if ( name_rec == NULL ) fmt_error( "Undefined segment name" );
return( name_rec->name );
}
char *grp_name( index )
int index;
{
GRP_T *grp_rec;
NAME_T *name_rec;
grp_search.index = index;
grp_rec = (GRP_T *)find( (char *)&grp_search, group_tree,
TC grp_compare, NULL );
if ( grp_rec == NULL ) fmt_error( "Undefined group" );
name_search.index = grp_rec->name;
name_rec = (NAME_T *)find( (char *)&name_search, name_tree,
TC name_compare, NULL );
if ( name_rec == NULL ) fmt_error( "Undefined group name" );
return( name_rec->name );
}
char *mode_name( mode, index )
int mode;
int index;
{
word dummy;
if ( index == 0 ) {
return( "NOTHING" );
}
switch( mode ) {
case SEGMENT: return( seg_name(index,&dummy) );
case GROUP: return( grp_name(index) );
case LOCATION: return( cseg_name );
case EXTERNAL:
case FRAME:
case TARGET:
case NONE: return( NULL );
}
return(NULL);
}
void assume( seg_reg, data_mode, data_index )
int seg_reg;
int data_mode;
int data_index;
{
char *seg_name;
extern char *sregsc[];
char operand[100];
seg_name = mode_name( data_mode, data_index );
if (seg_name && compatibility != 2 && pass == 3 ) {
out_opcode( "assume" );
sprintf( operand, "%s %s", sregsc[seg_reg], seg_name );
out_operand( operand );
out_endline();
}
}
void adjust_assumes()
{
int seg_reg;
int new_mode;
int new_index;
for ( seg_reg = 0; seg_reg < MAX_SEG_REGS; seg_reg++ ) {
new_mode = seg_rec->new_mode [seg_reg];
new_index = seg_rec->new_index[seg_reg];
if ( new_mode != seg_rec->prv_mode [seg_reg] ||
new_index != seg_rec->prv_index[seg_reg] ) {
assume( seg_reg, new_mode, new_index );
seg_rec->prv_mode [seg_reg] = new_mode;
seg_rec->prv_index[seg_reg] = new_index;
}
}
}
void abort_assumes()
{
int seg_reg;
for ( seg_reg = 0; seg_reg < MAX_SEG_REGS; seg_reg++ ) {
seg_rec->new_mode [seg_reg] = seg_rec->prv_mode [seg_reg];
seg_rec->new_index[seg_reg] = seg_rec->prv_index[seg_reg];
}
}
void get_seg( result, fixup, ref_mode, data, seg_reg )
char *result;
FIX_T *fixup;
int ref_mode;
void *data;
int seg_reg;
{
char *this_name;
int form;
int mode;
int index;
int ref_seg;
EXT_T *ext_rec;
PUB_T *pub_rec;
form = fixup->form;
mode = fixup->a_mode;
index = fixup->a_index;
strcpy( result, "" );
if ( mode == TARGET || mode == NONE ) {
return;
}
/*
** Check for Externals with implied or lacking segment
** This means that the fixup tells that the external was defined in
** that segment (for implied, SI:EI). Or that the external was defined
** outside any segment (for lacking, EI:EI).
*/
if ( fixup->b_mode == EXTERNAL ) {
ext_rec = data;
if ( mode == EXTERNAL ) {
/* Must be EI:EI */
ext_rec->used = -1; /* Remove from any segments! */
return;
}
if ( mode == SEGMENT ) {
ext_rec->pos_abs = FALSE;
if ( ref_mode != 0 ) {
/* Must be Segment:EI */
if ( pass == 1 && ext_rec->used == 0 ) {
sex_insert( index, ext_rec );
ext_rec->used = index;
}
if ( ext_rec->used == index ) {
return;
}
}
}
} else {
if ( fixup->b_mode == SEGMENT ) {
pub_rec = data;
if ( ref_mode == 2 && (ref_mode == 1 && form == POINTER) ) {
if ( pub_rec->seg_idx == index ) {
return;
}
}
}
}
/*
** On first important fixup, assign the "ASSIGN xx:" values
*/
if ( ref_mode == 0 || (ref_mode == 1 && form != POINTER) ) {
ref_seg = seg_reg - ES; /* Convert to 0,1,2,3,etc */
seg_rec->new_mode [ref_seg] = mode;
seg_rec->new_index[ref_seg] = index;
if ( mode == SEGMENT ) {
if ( fixup->b_mode == EXTERNAL && ext_rec->used == index ) {
return;
}
}
if ( mode == SEGMENT || mode == GROUP ) {
if ( fixup->b_mode == SEGMENT || fixup->b_mode == EXTERNAL ) {
return;
}
}
/*
** Frame on a code reference is always taken from the assume?
*/
}
if ( form == BASE ) {
if ( fixup->b_mode == mode && fixup->b_index == index ) {
return;
}
}
this_name = mode_name( mode, index );
if ( this_name ) {
sprintf( result, "%s:", this_name );
return;
} else {
return;
}
}
PUB_T *check_public( mode, index, displacement, label_char )
int mode;
int index;
long displacement;
char label_char;
{
PUB_T *new_pub_rec;
NODE_T *new_node;
DAT_T dat_search;
DAT_T *dat_rec;
NODE_T *dat_node;
FIX_T *fix_rec;
NODE_T *fix_node;
int ref_seg;
char label_name[10];
dword disp;
int fix_count;
#ifdef DEBUG
printf("--> check_public for [%04X:%04lX]\n", index, displacement );
#endif
if ( over_seg == -1 ) {
ref_seg = 2;
} else {
ref_seg = over_seg;
}
if ( displacement < 0L ) {
disp = 0L;
} else {
disp = displacement;
}
if ( mode == 2 ) {
index = seg_rec->prv_index[ref_seg];
}
pub_search.seg_idx = index;
pub_search.offset = disp;
new_pub_rec = (PUB_T *)find( (char *)&pub_search, public_tree,
TC pub_compare, &new_node );
if ( new_pub_rec ) {
return( new_pub_rec );
}
/*
** If the address is just slightly past another public symbol, and
** the address is less than the public symbols address + its size,
** then it is probably a "public+x" type fixup.
*/
if ( new_node != public_tree ) {
new_pub_rec = (PUB_T *)new_node->data;
if ( new_pub_rec->seg_idx == index ) {
if ( new_pub_rec->offset + type_to_size(new_pub_rec->type) > disp ) {
return( new_pub_rec );
}
}
}
/*
** Find the data record that that symbol probably belongs in
*/
dat_search.seg_idx = index;
dat_search.offset = disp;
dat_rec = (DAT_T *)find( (char *)&dat_search, data_tree,
TC dat_compare, &dat_node );
if ( dat_node && dat_node != data_tree ) {
dat_rec = (DAT_T *)dat_node->data;
if ( dat_rec->seg_idx == index
&& dat_rec->offset+dat_rec->length > disp ) {
/*
** Make sure the symbol is not in the middle of a fixup
*/
fix_search.seg_idx = index;
fix_search.dat_offset = dat_rec->offset;
fix_search.offset = (int)(disp - (dword)dat_rec->offset);
fix_rec = (FIX_T *)find( (char *)&fix_search, fix_tree,
TC fix_compare, &fix_node );
if ( !fix_rec ) {
if ( fix_node != fix_tree ) {
fix_rec = (FIX_T *)fix_node->data;
if ( fix_rec->seg_idx == index
&& fix_rec->dat_offset == dat_rec->offset ) {
fix_count = fix_type[fix_rec->form].num_bytes;
/*
** BASE types do not get larger
*/
if ( fix_rec->extended && fix_rec->form != BASE ) {
fix_count += 2;
}
if ( fix_search.offset > fix_rec->offset
&& fix_search.offset < fix_rec->offset+fix_count ) {
return( new_pub_rec );
}
}
}
}
/*
** Make sure that public is not being placed inside an
** iterated data block. If it is, then retreat to the
** start of the iterated data block. In this way, labels
** will never be generated inside iterated data blocks.
*/
if ( dat_rec->type == ITERATED ) {
if ( new_node == public_tree ) {
return( NULL );
}
if ( new_pub_rec->seg_idx != index ) {
return( NULL );
}
if ( new_pub_rec->offset >= dat_rec->offset ) {
return( new_pub_rec );
}
disp = dat_rec->offset;
}
}
}
/*
** Create a local label (only happens on 1st pass!)
*/
label_count++;
if ( compatibility == 2 ) {
sprintf( label_name, "@%c%d", label_char, label_count );
} else {
sprintf( label_name, "$%c%d", label_char, label_count );
}
#ifdef DEBUG
printf("Creating a new symbol <%s> at %d:%04X\n", label_name, index, disp);
#endif
new_node = pub_insert( index, disp, label_name, LOCAL, FALSE );
new_pub_rec = (PUB_T *)find( (char *)&pub_search, public_tree,
TC pub_compare, NULL );
if ( (pub_node == public_tree || index < pub_rec->seg_idx ||
(index == pub_rec->seg_idx && disp < pub_rec->offset)) &&
(index > segment || (index == segment && disp > inst_offset)) ) {
pub_node = new_node;
pub_rec = new_pub_rec;
}
if ( index == segment && disp == inst_offset ) {
last_pub_rec = new_pub_rec;
}
return( new_pub_rec );
}
int find_member( text, structure, offset )
char *text;
STRUC_T *structure;
long *offset;
{
int type;
int mem_cnt;
long dup_cnt;
long this_size;
char *cp;
char ch;
mem_cnt = 0;
cp = structure->form;
while ( (ch=*cp) != '\0' ) {
switch( ch ) {
case '(':
dup_cnt = atol( cp+1 );
break;
case ',':
type = atoi( cp+1 );
break;
case ')':
this_size = type_to_size(type)*dup_cnt;
if ( *offset < this_size ) {
sprintf( text, ".s%dm_%d", structure->index, mem_cnt );
return( type );
}
*offset -= this_size;
mem_cnt++;
default:
break;
}
cp++;
}
strcpy( text, ".past struct" );
return( UNKNOWN );
}
void get_target( result, fixup, mode, data, pre_name, type, assign,
type_known, seg_reg )
char *result; /* Output string */
FIX_T *fixup; /* Fixup to figure out */
int mode; /* 0 = Data Deref, 1 = Code, 2 = Data Ref */
long data; /* Value added (fixups get added onto this) */
int pre_name; /* Are the fixup type words needed? */
int type; /* type of value pointed to (word ptr, etc) */
int assign; /* Assign type if needed? */
int *type_known; /* Is the "word ptr" text needed? (result) */
int seg_reg; /* Segment register used */
{
int index;
PUB_T *pub_rec;
EXT_T ext_search;
EXT_T *ext_rec;
STRUC_T *pub_struct;
char *prefix;
char this_seg[NAMESIZE+1+1]; /* 1 for ':', 1 for \0 */
char this_member[NAMESIZE+1+1]; /* 1 for ., 1 for \0 */
word seg_size;
char *this_name;
char *this_comment;
int this_type;
char sign;
long disp;
#ifdef DEBUG
printf("-> get_target for [%04X:%04X]\n", fix_rec->seg_idx, fix_rec->dat_offset );
#endif
disp = data;
this_seg[0] = '\0';
this_member[0] = '\0';
this_comment = "";
/*
** Fixups cannot have a displacement value (stored with the fixup)
** AND a value added (stored in the image to which the fixup is added)
*/
if ( fixup->displacement != 0L ) {
if ( disp != 0L ) {
this_comment = "[MULTIPLE FIXUP]";
}
disp += fixup->displacement;
}
if ( pre_name ) {
prefix = fix_type[fixup->form].prefix;
} else {
prefix = "";
}
index = fixup->b_index;
switch( fixup->b_mode ) {
case SEGMENT: /* Segment Index and Displacement */
if ( fixup->form != BASE ) {
/* PUBLIC names will be stored as segment + offset */
pub_rec = check_public( 0, index, disp, 'S' );
if ( pub_rec ) {
this_name = pub_rec->name;
disp -= (long)pub_rec->offset;
pub_struct = pub_rec->structure;
if ( pub_struct ) {
this_type = find_member( this_member, pub_struct,
&disp );
} else {
if ( assign && ((type <= FAR && pub_rec->type > FAR)
|| pub_rec->type == UNKNOWN) ) {
pub_rec->type = type;
}
this_type = pub_rec->type;
}
if ( this_type != type ) {
*type_known = FALSE;
} else {
*type_known = TRUE;
}
get_seg( this_seg, fixup, mode, pub_rec, seg_reg );
break;
}
}
this_name = seg_name(index,&seg_size);
if ( fixup->form == BASE && fixup->displacement != 0 ) {
prefix = ""; /* MASM generates seg length, if */
disp -= seg_size; /* "SEG" is missing, do the same */
}
this_seg[0] = '\0';
*type_known = TRUE;
break;
case GROUP: /* Group Index and Displacement */
this_name = grp_name(index);
*type_known = TRUE;
get_seg( this_seg, fixup, mode, NULL, seg_reg );
break;
case EXTERNAL: /* External Index and Displacement */
ext_search.index = index;
ext_rec = (EXT_T *)find( (char *)&ext_search,
extern_tree, TC ext_compare, NULL );
if ( ext_rec == NULL ) fmt_error( "Undefined external" );
this_name = ext_rec->name;
if ( assign && ((type <= FAR && ext_rec->type > FAR)
|| ext_rec->type == UNKNOWN) ) {
ext_rec->type = type;
}
if ( ext_rec->type != type ) {
*type_known = FALSE;
} else {
*type_known = TRUE;
}
get_seg( this_seg, fixup, mode, ext_rec, seg_reg );
break;
case FRAME: /* Frame Number and Displacement */
get_seg( this_seg, fixup, mode, NULL, seg_reg );
break;
}
if ( disp == 0 ) {
/* ;* */ sprintf( result, "%s%s%s%s%s", prefix, this_seg,
this_name, this_member, this_comment );
} else {
if ( disp > 0L ) {
sign = '+';
} else {
sign = '-';
disp = -disp;
}
if ( disp > 32767L || disp < -32768L ) {
sprintf( result, "%s%s%s%s %c 0%08lXh%s",
prefix, this_seg,
this_name, this_member,
sign, disp,
this_comment );
} else {
sprintf( result, "%s%s%s%s %c 0%04lXh%s",
prefix, this_seg,
this_name, this_member,
sign, disp,
this_comment );
}
}
#ifdef DEBUG
printf("<- get_target [%04X:%04X]\n", fix_rec->seg_idx, fix_rec->dat_offset );
#endif
}
int get_fix( result, mode, pre_name, size_bytes, size, assign,
size_known, seg_reg )
char *result; /* Resulting name will go here */
int mode; /* 0 = Data Deref, 1 = Code, 2 = Data Ref */
int pre_name; /* Fixup type words needed? */
int size_bytes; /* Word size (386=4 others=2) */
int size; /* Size of expected value */
int assign; /* TRUE to set size, FALSE to ignore */
int *size_known; /* Is "word ptr" text needed? */
int seg_reg; /* Segment register used */
{
dword data;
dword more;
int fix_count;
size_bytes = size_bytes;
fix_count = fix_type[fix_rec->form].num_bytes;
/*
** BASE types do not get larger
*/
if ( fix_rec->extended && fix_rec->form != BASE ) {
fix_count += 2;
}
switch( fix_count ) {
case 1: data = buff_getc();
break;
case 2: data = buff_getc();
data += (buff_getc() << 8);
break;
case 4: data = buff_getc();
data += (buff_getc() << 8);
data += (buff_getc() << 16);
data += (buff_getc() << 24);
break;
case 6: data = buff_getc();
data += (buff_getc() << 8);
data += (buff_getc() << 16);
data += (buff_getc() << 24);
more = buff_getc();
more += (buff_getc() << 8);
break;
default:
fmt_error( "Invalid fixup type" );
break;
}
get_target( result, fix_rec, mode, data, pre_name, size, assign,
size_known, seg_reg );
fix_advance();
return( fix_count );
}